﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Diagnostics.Contracts;

namespace System.Linq.Expressions
{
	internal sealed class ExpressionExistsVisitor : ExpressionVisitor
	{

		internal ExpressionExistsVisitor( Expression lookingFor )
		{
			this.LookingFor = lookingFor;
			this.LookForType = null;
		}

		internal ExpressionExistsVisitor( ExpressionType lookForType )
		{
			this.LookForType = lookForType;
			this.LookingFor = null;
		}

		public Expression LookingFor
		{ get; private set; }

		public ExpressionType? LookForType
		{ get; private set; }

		public bool Found
		{ get; private set; }

		public bool TryFindOn( Expression resource )
		{
			this.Found = false;
			this.Visit( resource );
			return this.Found;
		}

		public override Expression Visit( Expression node )
		{
			if ( node != null )
			{
				if ( this.LookingFor != null )
					this.Found |= this.LookingFor.Equals( node );

				if ( this.LookForType.HasValue )
					this.Found |= node.NodeType == this.LookForType.Value;
			}

			return base.Visit( node );
		}
	}

	public static class ExpressionExistsExtensions
	{

		/// <summary>
		/// Procura por <paramref name="lookingFor"/> na expressão <paramref name="resource"/>.
		/// </summary>
		/// <param name="resource"></param>
		/// <param name="lookingFor"></param>
		/// <returns></returns>
		public static bool Has( this Expression resource, Expression lookingFor )
		{
			if ( resource != null && lookingFor != null )
			{
				var visitor = new ExpressionExistsVisitor( lookingFor );
				return visitor.TryFindOn( resource );
			}
			else
				return false;
		}

		/// <summary>
		/// Verifica se possui o <paramref name="nodeType"/> na expressão <paramref name="resource"/>.
		/// </summary>
		/// <param name="resource"></param>
		/// <param name="nodeType"></param>
		/// <returns></returns>
		public static bool Has( this Expression resource, ExpressionType nodeType )
		{
			if ( resource != null )
			{
				var visitor = new ExpressionExistsVisitor( nodeType );
				return visitor.TryFindOn( resource );
			}
			else
				return false;
		}
	}
}
